package com.sihai.ehr.web.action.ajax;

import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;

import com.sihai.core.LimitedList;
import com.sihai.core.beans.BeanInject;
import com.sihai.ehr.model.biz.Attendance;
import com.sihai.ehr.model.biz.AttendanceErp;
import com.sihai.ehr.model.biz.EmployeeinfoWork;
import com.sihai.ehr.model.biz.ExamAward;
import com.sihai.ehr.model.biz.ExamStatistics;
import com.sihai.ehr.model.biz.SalaryCustom;
import com.sihai.ehr.model.biz.SalaryCustomConfig;
import com.sihai.ehr.model.biz.SalaryCustomDetail;
import com.sihai.ehr.model.biz.SalaryIndividualTax;
import com.sihai.ehr.model.biz.SalaryIndividualTaxRadix;
import com.sihai.ehr.model.biz.SalaryIndividualTaxRule;
import com.sihai.ehr.model.biz.SalaryOvertime;
import com.sihai.ehr.model.biz.SalaryPerformance;
import com.sihai.ehr.model.biz.SalarySocialInsurance;
import com.sihai.ehr.model.biz.SalarySocialInsuranceDetail;
import com.sihai.ehr.model.biz.SalaryStatistics;
import com.sihai.ehr.model.biz.SalaryStatisticsDetail;
import com.sihai.ehr.model.biz.SalaryStructure;
import com.sihai.ehr.model.biz.SalaryStructureDetail;
import com.sihai.ehr.model.sys.AuditStatus;
import com.sihai.ehr.model.sys.ExaminePeriodEnum;
import com.sihai.ehr.model.sys.Organization;
import com.sihai.ehr.model.sys.SalaryAttendanceEnum;
import com.sihai.ehr.model.sys.SalaryFrameworkEnum;
import com.sihai.ehr.model.sys.SalaryInsurancePayEnum;
import com.sihai.ehr.model.sys.SalaryInsuranceTypeEnum;
import com.sihai.ehr.model.sys.SalaryLinkedEnum;
import com.sihai.ehr.model.sys.SalaryStructureEnum;
import com.sihai.ehr.service.AttendanceErpService;
import com.sihai.ehr.service.AttendanceService;
import com.sihai.ehr.service.EmployeeService;
import com.sihai.ehr.service.ExamAwardService;
import com.sihai.ehr.service.ExamPeriodService;
import com.sihai.ehr.service.ExamStatisticsService;
import com.sihai.ehr.service.IndividualTaxService;
import com.sihai.ehr.service.OrganizationService;
import com.sihai.ehr.service.OvertimeTaxService;
import com.sihai.ehr.service.SalaryCustomService;
import com.sihai.ehr.service.SalaryInsuranceService;
import com.sihai.ehr.service.SalaryPerformanceService;
import com.sihai.ehr.service.SalaryStatisticService;
import com.sihai.ehr.service.SalaryStructService;
import com.sihai.ehr.web.action.EHRAction;
import com.sihai.ehr.web.pojo.SalaryLinkedPojo;
import com.sihai.ehr.web.pojo.StaffSearchPojo;

/**
 * 薪资AJAX处理控制器
 * 
 * @author henry
 * 
 */
public class SalaryJsonControl extends EHRAction {
	/**
	 * 
	 */
	private static final long serialVersionUID = -1697698367722622599L;

	private Log log = LogFactory.getLog(SalaryJsonControl.class);

	/** 组织架构服务 */
	@BeanInject
	private OrganizationService organizationService;
	/** 薪资框架结构 */
	@BeanInject
	private SalaryStructService salaryStructService;

	/** 自定义薪资框架结构 */
	@BeanInject
	private SalaryCustomService salaryCustomService;

	/** 社保管理服务 */
	@BeanInject
	private SalaryInsuranceService salaryInsuranceService;
	/** 绩效周期服务 */
	@BeanInject
	private ExamPeriodService examPeriodService;
	/** 绩效统计服务 */
	@BeanInject
	private ExamStatisticsService examStatisticsService;
	/** 薪资绩效服务 */
	@BeanInject
	private SalaryPerformanceService salaryPerformanceService;

	/** 薪资统计服务 */
	@BeanInject
	private SalaryStatisticService salaryStatisticService;

	/** 个人所得税服务 */
	@BeanInject
	private IndividualTaxService individualTaxService;
	/** 加班费服务 */
	@BeanInject
	private OvertimeTaxService overtimeTaxService;
	/** 考勤服务 */
	@BeanInject
	private AttendanceService attendanceService;
	/** ERP服务 */
	@BeanInject
	private AttendanceErpService attendanceErpService;

	/** 员工服务 */
	@BeanInject
	private EmployeeService employeeService;
	/** 员工奖惩服务 */
	@BeanInject
	private ExamAwardService examAwardService;

	private SalaryFrameworkEnum linkedDataType;
	List<SalaryLinkedPojo> linkedPojos;

	/** 个税起点 */
	private int taxBase = 3500;
	/** 发放薪资计算月份必须为 */
	private String mBMonthlyExam = ",12,2,4,6,8,10,";
	/** 季度 */
	private String mSeasonExam = ",12,3,6,9,";
	/** 半年 */
	private String mSemiyearlyExam = ",12,6,";
	/** 一年 */
	private String mAnnuallyExam = ",12,";
	private int year;
	private int month;
	/** 需要结算的员工任职编号 */
	private Long workId;
	/** 职位编号　 */
	private Long dutyId;
	/** 计算总记录数 */
	private int totalCount;
	/** 当前位置 */
	private int currentPos;
	private int successCount = 0;
	private int failureCount = 0;

	/** 个税基数 */
	private SalaryIndividualTaxRadix individualTaxRadix;
	/** 个税区间 */
	private List<SalaryIndividualTaxRule> individualTaxRules;

	/**
	 * 查询薪资结构员工数
	 * 
	 * @return
	 */
	@Action(value = "/ajax/query_employeeofcustomid", results = { @Result(name = "success", type = "plainText") })
	public String queryEmployeeNumberBySalaryCustomId() {
		try {
			Long totalCount = salaryCustomService.getTotalCountBySalaryCustomId(getParameter("customId") == null ? -1 : Long.parseLong(getParameter("customId")));
			HttpServletResponse response = ServletActionContext.getResponse();
			response.getWriter().write(totalCount.toString());
			response.getWriter().flush();
			response.getWriter().close();

			return SUCCESS;
		} catch (Exception e) {
			return null;
		}
	}

	@Action(value = "/ajax/salary_linkeddata_list", results = { @Result(name = "success", type = "json", params = { "root", "linkedPojos" }) })
	public String getLinkedDataTOJson() throws Exception {
		try {
			if (linkedDataType != null) {
				linkedPojos = new LimitedList<SalaryLinkedPojo>();
				if (linkedDataType == SalaryFrameworkEnum.social_insurance) {
					List<SalarySocialInsurance> insurances = salaryInsuranceService.searchInsuranceList(organizationId);
					if (insurances != null && insurances.size() > 0) {
						for (SalarySocialInsurance salarySocialInsurance : insurances) {
							linkedPojos.add(new SalaryLinkedPojo(salarySocialInsurance.getId(), salarySocialInsurance.getTitle()));
						}
					}
				} else if (linkedDataType == SalaryFrameworkEnum.examine) {
					SalaryAttendanceEnum[] attendanceEnums = SalaryAttendanceEnum.values();
					for (int i = 0; i < attendanceEnums.length; i++) {
						linkedPojos.add(new SalaryLinkedPojo((long) attendanceEnums[i].getValue(), attendanceEnums[i].getName()));
					}
				} else if (linkedDataType == SalaryFrameworkEnum.individual_tax) {
					List<SalaryIndividualTax> individualTaxs = individualTaxService.query(organizationId, null, null);
					if (individualTaxs != null && individualTaxs.size() > 0) {
						for (SalaryIndividualTax tax : individualTaxs) {
							linkedPojos.add(new SalaryLinkedPojo(tax.getId(), tax.getTitle()));
						}
					}

				} else if (linkedDataType == SalaryFrameworkEnum.overtime) {
					List<SalaryOvertime> overtimes = overtimeTaxService.query(organizationId, null, null);
					if (overtimes != null && overtimes.size() > 0) {
						for (SalaryOvertime overtime : overtimes) {
							linkedPojos.add(new SalaryLinkedPojo(overtime.getId(), overtime.getTitle()));
						}
					}
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return SUCCESS;
	}

	/**
	 * 薪资计算回调
	 * 
	 * @return
	 * @throws Exception
	 */
	@Action(value = "/ajax/salary_compute_callback", results = { @Result(name = "success", type = "plainText") })
	public String handleSalaryComputeCallback() throws Exception {
		HttpServletRequest request = ServletActionContext.getRequest();
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		sb.append("\"totalCount\":").append(request.getSession().getAttribute("totalCount"));
		sb.append(",\"currentPos\":").append(request.getSession().getAttribute("currentPos"));
		sb.append(",\"successCount\":").append(request.getSession().getAttribute("successCount"));
		sb.append(",\"failureCount\":").append(request.getSession().getAttribute("failureCount"));
		sb.append("}");
		HttpServletResponse response = ServletActionContext.getResponse();
		response.getWriter().write(sb.toString());
		response.getWriter().flush();
		response.getWriter().close();
		return SUCCESS;
	}

	/**
	 * 计算薪资
	 * 
	 * @return
	 * @throws Exception
	 */
	@Action(value = "/ajax/salary_compute", results = { @Result(name = "success", type = "plainText") })
	public String handleSalaryCompute() throws Exception {
		Calendar mCalendar = Calendar.getInstance();
		Organization topOrg = organizationService.get(organizationId).getTopOrganization();
		// 读取个税计算表达式
		individualTaxRadix = individualTaxService.getRadix(topOrg == null ? organizationId : topOrg.getId());
		individualTaxRules = individualTaxService.queryTaxRule(topOrg == null ? organizationId : topOrg.getId(), null, null);
		// 读取薪资绩效服务数据列表
		List<SalaryPerformance> performances = salaryPerformanceService.find(topOrg == null ? organizationId : topOrg.getId(), null, null);
		HttpServletRequest request = ServletActionContext.getRequest();
		try {
			// 单个员工计算
			if (workId != null && workId > 0) {

				EmployeeinfoWork mWork = employeeService.getEmployeeinfoWork(workId);
				if (mWork != null) {
					computeSingleEmployeeSalary(mWork, mCalendar, performances);
				}
				totalCount = 1;
				currentPos = 1;
				request.getSession().setAttribute("totalCount", totalCount);
				request.getSession().setAttribute("successCount", successCount);
				request.getSession().setAttribute("failureCount", failureCount);
				request.getSession().setAttribute("currentPos", currentPos);
			} else {
				StaffSearchPojo search = new StaffSearchPojo();
				search.setDepartment(organizationId);
				search.setDuty(dutyId);
				List<EmployeeinfoWork> employeeinfoWorks = employeeService.searchEmployeeinfoWorks(search, organizationId, "1", null, null);
				if (employeeinfoWorks != null && employeeinfoWorks.size() > 0) {
					request.getSession().setAttribute("totalCount", employeeinfoWorks.size());
					for (EmployeeinfoWork employeeinfoWork : employeeinfoWorks) {
						if(currentPos >=18){
							System.out.println("xxx");
						}
						computeSingleEmployeeSalary(employeeinfoWork, mCalendar, performances);
						request.getSession().setAttribute("successCount", successCount);
						request.getSession().setAttribute("failureCount", failureCount);
						request.getSession().setAttribute("currentPos", currentPos);
						currentPos++;
					}
				}
			}
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error(e);
			}
			return ERROR;
		}

		return SUCCESS;
	}

	/**
	 * 计算单个员工薪资
	 * 
	 * @param workId
	 * @param mCalendar
	 * @param performances
	 */
	private void computeSingleEmployeeSalary(EmployeeinfoWork mWork, Calendar mCalendar, List<SalaryPerformance> performances) {
		if (mWork == null) {
			if (log.isErrorEnabled()) {
				log.error("员工任职对象为空" + mWork);
			}
			failureCount++;
			return;
		}
		// 薪资统计
		SalaryStatistics mStatistics = salaryStatisticService.get(mWork.getId(), year, month);
		if (mStatistics == null) {
			mStatistics = new SalaryStatistics();
			mStatistics.setYear(year);
			mStatistics.setMonth(month);
			mStatistics.setEmployeeinfoWork(mWork);
		} else {
			// 删除明细数据
			salaryStatisticService.deleteSalaryStatisticDetails(mStatistics.getId());
		}
		// 考勤数据
		Attendance attendance = attendanceService.getAttendanceByWorkdId(mWork.getId(), year, month);

		Float totalWages = 0F; // 总薪资
		Float[] companyPayWages = { 0f }; // 公司缴费:引用传递
		SalaryStructure structure = mWork.getGrade() != null ? mWork.getGrade().getSalaryStructure() : null;
		// 延迟计算列表:比如挂勾数据为结算比例来计算的
		Set<Object> lazyDetails = new HashSet<Object>();

		// ////////////////////////////////////////////
		// 第一部份计算基础数据(薪资总和不挂勾的数据项)
		// ////////////////////////////////////////////

		/**
		 * 薪资框架中计算块
		 */
		if (structure != null && structure.getId() != null && structure.getDetails() != null && structure.getDetails().size() > 0) {
			Set<SalaryStructureDetail> details = structure.getDetails();
			if (details != null && details.size() > 0) {
				Iterator<SalaryStructureDetail> it = details.iterator();
				while (it.hasNext()) {
					SalaryStructureDetail detail = it.next();
					// 考核周期是否应该发放
					ExaminePeriodEnum type = detail.getPeriodType();
					int curMonth = month;
					if (type == ExaminePeriodEnum.bimonthly && !mBMonthlyExam.contains("," + curMonth + ",")) {
						continue;
					} else if (type == ExaminePeriodEnum.season && !mSeasonExam.contains("," + curMonth + ",")) {
						continue;
					} else if (type == ExaminePeriodEnum.semiyearly && !mSemiyearlyExam.contains("," + curMonth + ",")) {
						continue;
					} else if (type == ExaminePeriodEnum.annually && !mAnnuallyExam.contains("," + curMonth + ",")) {
						continue;
					}

					if (detail.getPeriodComputeMode() > 0 && detail.getPeriodComputeMode() < mCalendar.get(Calendar.DATE)) {
						continue;
					}
					// 符合周期计算
					// 计算细节
					SalaryStatisticsDetail statisticsDetail = new SalaryStatisticsDetail();
					statisticsDetail.setSchemeTitle(detail.getSchemeTitle());
					statisticsDetail.setLinkedDataId(detail.getLinkedDataId());
					statisticsDetail.setLinkedDataType(detail.getLinkedDataType());
					statisticsDetail.setLinkedDataTitle(detail.getLinkedDataTitle());
					statisticsDetail.setStructType(detail.getStructType());
					float itemWages = 0f;
					switch (detail.getLinkedDataType()) {
					case no_link: // 无挂勾数据-直接相加
						itemWages = detail.getFixedCost();
						break;
					case basic_salary: // 底薪－直接相加
						itemWages = mWork.getGradeLevel().getGradePay();
						break;
					case social_insurance: // 社保
						if (detail.getLinkedDataId() <= 0) {
							itemWages = detail.getFixedCost();
						} else {
							itemWages = computeInsurance(detail, lazyDetails, mWork, performances, type, year, month, -1f, companyPayWages);
						}
						break;
					case examine: // 考核数据源计算方式
						if (detail.getLinkedDataId() < 0) {
							itemWages = detail.getFixedCost();
						} else if (attendance != null) {
							SalaryAttendanceEnum mAttendanceEnum = SalaryAttendanceEnum.getNameByvalue(Integer.parseInt(detail.getLinkedDataId().toString()));
							switch (mAttendanceEnum) {
							case absence_days:
								itemWages = (attendance.getAbsenceLeaveDays() == null ? 0 : attendance.getAbsenceLeaveDays()) * detail.getUnitCost();
								break;
							case absent_days:
								itemWages = (attendance.getAbsentDays() == null ? 0 : attendance.getAbsentDays()) * detail.getUnitCost();
								break;
							case adjust_days:
								itemWages = (attendance.getAdjustDays() == null ? 0 : attendance.getAdjustDays()) * detail.getUnitCost();
								break;
							case adjust_hours:
								itemWages = (attendance.getAdjustLeave() == null ? 0 : attendance.getAdjustLeave()) * detail.getUnitCost();
								break;
							case delay_hours:
								itemWages = (attendance.getDelayLeave() == null ? 0 : attendance.getDelayLeave()) * detail.getUnitCost();
								break;
							case delay_times:
								itemWages = (attendance.getDelayTimes() == null ? 0 : attendance.getDelayTimes()) * detail.getUnitCost();
								break;
							case early_times:
								itemWages = (attendance.getEarlyTimes() == null ? 0 : attendance.getEarlyTimes()) * detail.getUnitCost();
								break;
							case early_hours:
								itemWages = (attendance.getEarlyLeave() == null ? 0 : attendance.getEarlyLeave()) * detail.getUnitCost();
								break;
							case funeral_days:
								itemWages = (attendance.getFuneralLeaveDays() == null ? 0 : attendance.getFuneralLeaveDays()) * detail.getUnitCost();
								break;
							case furlough_days:
								itemWages = (attendance.getFurloughLeaveDays() == null ? 0 : attendance.getFurloughLeaveDays()) * detail.getUnitCost();
								break;
							case injury_days:
								itemWages = (attendance.getInjuryDays() == null ? 0 : attendance.getInjuryDays()) * detail.getUnitCost();
								break;
							case injury_hours:
								itemWages = (attendance.getInjuryLeave() == null ? 0 : attendance.getInjuryLeave()) * detail.getUnitCost();
								break;
							case marry_days:
								itemWages = (attendance.getMarryLeaveDays() == null ? 0 : attendance.getMarryLeaveDays()) * detail.getUnitCost();
								break;
							case maternity_days:
								itemWages = (attendance.getMaternityLeaveDays() == null ? 0 : attendance.getMaternityLeaveDays()) * detail.getUnitCost();
								break;
							case other_days:
								itemWages = (attendance.getOtherLeaveDays() == null ? 0 : attendance.getOtherLeaveDays()) * detail.getUnitCost();
								break;
							case recard_times:
								itemWages = (attendance.getReCardTimes() == null ? 0 : attendance.getReCardTimes()) * detail.getUnitCost();
								break;
							case sick_days:
								itemWages = (attendance.getSickLeaveDays() == null ? 0 : attendance.getSickLeaveDays()) * detail.getUnitCost();
								break;
							case uncard_times:
								itemWages = (attendance.getUnCardTimes() == null ? 0 : attendance.getUnCardTimes()) * detail.getUnitCost();
								break;
							case wash_days:
								itemWages = (attendance.getWashDays() == null ? 0 : attendance.getWashDays()) * detail.getUnitCost();
								break;
							case wash_hours:
								itemWages = (attendance.getWashHours() == null ? 0 : attendance.getWashHours()) * detail.getUnitCost();
								break;
							case year_days:
								itemWages = (attendance.getYearLeaveDays() == null ? 0 : attendance.getYearLeaveDays()) * detail.getUnitCost();
								break;
							default:
								break;
							}
						}
						break;
					case erp_data: // erp数据源
						AttendanceErp mErp = attendanceErpService.getErpByWorkdId(mWork.getId(), year, month);
						if (mErp != null) {
							itemWages = mErp.getAmount();
						}
						break;
					case performance: // 绩效奖金
						// if (detail.getLinkedDataId() <= 0) {
						// itemWages = detail.getFixedCost();
						// } else {
						itemWages = computePerformance(mWork, performances, type, year, month);
						// }
						break;
					case individual_tax: // 个人所得税
						if (detail.getLinkedDataId() <= 0) {
							itemWages = detail.getFixedCost();
						} else {
							itemWages = computePersonalTax(detail, lazyDetails, mWork, performances, type, year, month, -1f);
						}
						break;
					case overtime: // 加班费
						if (detail.getLinkedDataId() <= 0) {
							itemWages = detail.getFixedCost();
						} else {
							SalaryOvertime overtime = overtimeTaxService.get(detail.getLinkedDataId());
							if (attendance != null) {
								itemWages = detail.getUnitCost() * overtime.getUsuallyOvertime() * (attendance.getOverTimeOneDays() == null ? 0 : attendance.getOverTimeOneDays())
										+ detail.getUnitCost() * overtime.getWeekendOvertime() * (attendance.getOverWeekendDays() == null ? 0 : attendance.getOverWeekendDays())
										+ detail.getUnitCost() * overtime.getHolidaysOvertime() * (attendance.getOverTimeTwoDays() == null ? 0 : attendance.getOverTimeTwoDays());
							}
						}
						break;
					default:
						break;
					}

					if (itemWages >= 0) {
						// 扣款
						if (detail.getStructType() == SalaryStructureEnum.detain) {
							totalWages -= itemWages;
						} else {
							totalWages += itemWages;
						}
						statisticsDetail.setSchemeSalary(itemWages);
						mStatistics.addDetailItem(statisticsDetail);
					}
				}
			}
		}

		/**
		 * 自定义薪资框架计算模块
		 */
		Long currentMillis = System.currentTimeMillis();
		List<SalaryCustomConfig> customConfigs = salaryCustomService.getSalaryCustomConfigByWorkId(mWork.getId(), null, null);
		if (customConfigs != null && customConfigs.size() > 0) {
			for (SalaryCustomConfig config : customConfigs) {
				SalaryCustom custom = null;
				if (config != null) {
					custom = salaryCustomService.get(config.getSalaryCustom().getId());
				}
				if (custom != null) {
					// 考核周期是否应该发放
					int curMonth = month;
					boolean isComputerable = true;
					// mCalendar.setTime(custom.getStartDate());
					mCalendar.setTime(new Date(currentMillis));
					if (custom.getPaymentType() == 0) { // 单次发放
						if (mCalendar.get(Calendar.YEAR) == year && mCalendar.get(Calendar.MONTH) + 1 == month) {
							// 进行单次计算
							isComputerable = true;
						}
					} else { // 周期性发放
						ExaminePeriodEnum type = custom.getPeriodPayType();
						if (type == ExaminePeriodEnum.bimonthly && !mBMonthlyExam.contains("," + curMonth + ",")) {
							isComputerable = false;
						} else if (type == ExaminePeriodEnum.season && !mSeasonExam.contains("," + curMonth + ",")) {
							isComputerable = false;
						} else if (type == ExaminePeriodEnum.semiyearly && !mSemiyearlyExam.contains("," + curMonth + ",")) {
							isComputerable = false;
						} else if (type == ExaminePeriodEnum.annually && !mAnnuallyExam.contains("," + curMonth + ",")) {
							isComputerable = false;
						}

						// 检测时间段
						if (custom.getStartDate().getTime() < currentMillis && custom.getEndDate().getTime() > currentMillis) {
							isComputerable = true;
						} else {
							isComputerable = false;
						}
					}
					if (isComputerable) {
						Set<SalaryCustomDetail> details = custom.getDetails();
						// 延迟计算列表:比如挂勾数据为结算比例来计算的
						// Set<SalaryCustomDetail> lazyDetails = new
						// HashSet<SalaryCustomDetail>();
						if (details != null && details.size() > 0) {
							Iterator<SalaryCustomDetail> it = details.iterator();
							while (it.hasNext()) {
								SalaryCustomDetail detail = it.next();
								// 符合周期计算
								// 计算细节
								SalaryStatisticsDetail statisticsDetail = new SalaryStatisticsDetail();
								statisticsDetail.setSchemeTitle(detail.getSchemeTitle());
								statisticsDetail.setLinkedDataId(detail.getLinkedDataId());
								statisticsDetail.setLinkedDataType(detail.getLinkedDataType());
								statisticsDetail.setLinkedDataTitle(detail.getLinkedDataTitle());
								statisticsDetail.setStructType(detail.getStructType());
								float itemWages = 0f;
								switch (detail.getLinkedDataType()) {
								case no_link: // 无挂勾数据-直接相加
									itemWages = detail.getFixedCost();
									break;
								case basic_salary: // 底薪－直接相加
									itemWages = mWork.getGradeLevel().getGradePay();
									break;
								case social_insurance: // 社保
									if (detail.getLinkedDataId() <= 0) {
										itemWages = detail.getFixedCost();
									} else {
										itemWages = computeInsuranceWithCustomMode(detail, lazyDetails, mWork, performances, custom.getPeriodPayType(), year, month, -1f,
												companyPayWages);
									}
									break;
								case examine: // 考核数据源计算方式
									if (detail.getLinkedDataId() < 0) {
										itemWages = detail.getFixedCost();
									} else if (attendance != null) {
										SalaryAttendanceEnum mAttendanceEnum = SalaryAttendanceEnum.getNameByvalue(Integer.parseInt(detail.getLinkedDataId().toString()));
										switch (mAttendanceEnum) {
										case absence_days:
											itemWages = (attendance.getAbsenceLeaveDays() == null ? 0 : attendance.getAbsenceLeaveDays()) * detail.getUnitCost();
											break;
										case absent_days:
											itemWages = (attendance.getAbsentDays() == null ? 0 : attendance.getAbsentDays()) * detail.getUnitCost();
											break;
										case adjust_days:
											itemWages = (attendance.getAdjustDays() == null ? 0 : attendance.getAdjustDays()) * detail.getUnitCost();
											break;
										case adjust_hours:
											itemWages = (attendance.getAdjustLeave() == null ? 0 : attendance.getAdjustLeave()) * detail.getUnitCost();
											break;
										case delay_hours:
											itemWages = (attendance.getDelayLeave() == null ? 0 : attendance.getDelayLeave()) * detail.getUnitCost();
											break;
										case delay_times:
											itemWages = (attendance.getDelayTimes() == null ? 0 : attendance.getDelayTimes()) * detail.getUnitCost();
											break;
										case early_times:
											itemWages = (attendance.getEarlyTimes() == null ? 0 : attendance.getEarlyTimes()) * detail.getUnitCost();
											break;
										case early_hours:
											itemWages = (attendance.getEarlyLeave() == null ? 0 : attendance.getEarlyLeave()) * detail.getUnitCost();
											break;
										case funeral_days:
											itemWages = (attendance.getFuneralLeaveDays() == null ? 0 : attendance.getFuneralLeaveDays()) * detail.getUnitCost();
											break;
										case furlough_days:
											itemWages = (attendance.getFurloughLeaveDays() == null ? 0 : attendance.getFurloughLeaveDays()) * detail.getUnitCost();
											break;
										case injury_days:
											itemWages = (attendance.getInjuryDays() == null ? 0 : attendance.getInjuryDays()) * detail.getUnitCost();
											break;
										case injury_hours:
											itemWages = (attendance.getInjuryLeave() == null ? 0 : attendance.getInjuryLeave()) * detail.getUnitCost();
											break;
										case marry_days:
											itemWages = (attendance.getMarryLeaveDays() == null ? 0 : attendance.getMarryLeaveDays()) * detail.getUnitCost();
											break;
										case maternity_days:
											itemWages = (attendance.getMaternityLeaveDays() == null ? 0 : attendance.getMaternityLeaveDays()) * detail.getUnitCost();
											break;
										case other_days:
											itemWages = (attendance.getOtherLeaveDays() == null ? 0 : attendance.getOtherLeaveDays()) * detail.getUnitCost();
											break;
										case recard_times:
											itemWages = (attendance.getReCardTimes() == null ? 0 : attendance.getReCardTimes()) * detail.getUnitCost();
											break;
										case sick_days:
											itemWages = (attendance.getSickLeaveDays() == null ? 0 : attendance.getSickLeaveDays()) * detail.getUnitCost();
											break;
										case uncard_times:
											itemWages = (attendance.getUnCardTimes() == null ? 0 : attendance.getUnCardTimes()) * detail.getUnitCost();
											break;
										case wash_days:
											itemWages = (attendance.getWashDays() == null ? 0 : attendance.getWashDays()) * detail.getUnitCost();
											break;
										case wash_hours:
											itemWages = (attendance.getWashHours() == null ? 0 : attendance.getWashHours()) * detail.getUnitCost();
											break;
										case year_days:
											itemWages = (attendance.getYearLeaveDays() == null ? 0 : attendance.getYearLeaveDays()) * detail.getUnitCost();
											break;
										default:
											break;
										}
									}
									break;
								case erp_data: // erp数据源
									AttendanceErp erp = attendanceErpService.getErpByWorkdId(mWork.getId(), year, month);
									if(erp != null){
										itemWages = erp.getAmount();
									}
									break;
								case performance: // 绩效奖金
									// if (detail.getLinkedDataId() <= 0) {
									// itemWages = detail.getFixedCost();
									// } else {
									itemWages = computePerformance(mWork, performances, custom.getPeriodPayType(), year, month);
									// }
									break;
								case individual_tax: // 个人所得税
									if (detail.getLinkedDataId() <= 0) {
										itemWages = detail.getFixedCost();
									} else {
										itemWages = computePersonalTaxWithCustomMode(detail, lazyDetails, mWork, performances, custom.getPeriodPayType(), year, month, -1f);
									}
									break;
								case overtime: // 加班费
									if (detail.getLinkedDataId() <= 0) {
										itemWages = detail.getFixedCost();
									} else {
										SalaryOvertime overtime = overtimeTaxService.get(detail.getLinkedDataId());
										if (attendance != null) {
											itemWages = detail.getUnitCost() * overtime.getUsuallyOvertime()
													* (attendance.getOverTimeOneDays() == null ? 0 : attendance.getOverTimeOneDays()) + detail.getUnitCost()
													* overtime.getWeekendOvertime() * (attendance.getOverWeekendDays() == null ? 0 : attendance.getOverWeekendDays())
													+ detail.getUnitCost() * overtime.getHolidaysOvertime()
													* (attendance.getOverTimeTwoDays() == null ? 0 : attendance.getOverTimeTwoDays());
										}
									}
									break;
								default:
									break;
								}

								if (itemWages >= 0) { // -1:表示总和框架挂勾
									// 扣款
									if (detail.getStructType() == SalaryStructureEnum.detain) {
										totalWages -= itemWages;
									} else {
										totalWages += itemWages;
									}
									statisticsDetail.setSchemeSalary(itemWages);
									mStatistics.addDetailItem(statisticsDetail);
								}
							}
						}
					}
				}
			}
		}

		// ////////////////////////////////////////////
		// 第二部份计算基础数据(薪资总和挂勾的数据项)
		// ////////////////////////////////////////////
		if (lazyDetails != null && lazyDetails.size() > 0) {
			float secondWages = 0f;
			for (Object obj : lazyDetails) {
				if (obj instanceof SalaryStructureDetail) {
					SalaryStructureDetail detail = (SalaryStructureDetail) obj;
					switch (detail.getLinkedDataType()) {
					case social_insurance:
						if (detail.getStructType() == SalaryStructureEnum.subsidy) {
							secondWages += computeInsurance(detail, null, mWork, performances, detail.getPeriodType(), year, month, totalWages, companyPayWages);
						} else {
							secondWages -= computeInsurance(detail, null, mWork, performances, detail.getPeriodType(), year, month, totalWages, companyPayWages);
						}
						break;
					case individual_tax:
						if (detail.getStructType() == SalaryStructureEnum.subsidy) {
							secondWages += computePersonalTax(detail, null, mWork, performances, detail.getPeriodType(), year, month, totalWages);
						} else {
							secondWages -= computePersonalTax(detail, null, mWork, performances, detail.getPeriodType(), year, month, totalWages);
						}
						break;
					default:
						break;
					}
					// 添加细节
					SalaryStatisticsDetail statisticsDetail = new SalaryStatisticsDetail();
					statisticsDetail.setSchemeTitle(detail.getSchemeTitle());
					statisticsDetail.setLinkedDataId(detail.getLinkedDataId());
					statisticsDetail.setLinkedDataType(detail.getLinkedDataType());
					statisticsDetail.setLinkedDataTitle(detail.getLinkedDataTitle());
					statisticsDetail.setStructType(detail.getStructType());
					statisticsDetail.setSchemeSalary(Math.abs(secondWages));
					mStatistics.addDetailItem(statisticsDetail);
				} else if (obj instanceof SalaryCustomDetail) {
					SalaryCustomDetail detail = (SalaryCustomDetail) obj;
					switch (detail.getLinkedDataType()) {
					case social_insurance:
						if (detail.getStructType() == SalaryStructureEnum.subsidy) {
							secondWages += computeInsuranceWithCustomMode(detail, null, mWork, performances, detail.getSalaryCustom().getPeriodPayType(), year, month, totalWages,
									companyPayWages);
						} else {
							secondWages -= computeInsuranceWithCustomMode(detail, null, mWork, performances, detail.getSalaryCustom().getPeriodPayType(), year, month, totalWages,
									companyPayWages);
						}
						break;
					case individual_tax:
						if (detail.getStructType() == SalaryStructureEnum.subsidy) {
							secondWages += computePersonalTaxWithCustomMode(detail, null, mWork, performances, detail.getSalaryCustom().getPeriodPayType(), year, month, totalWages);
						} else {
							secondWages -= computePersonalTaxWithCustomMode(detail, null, mWork, performances, detail.getSalaryCustom().getPeriodPayType(), year, month, totalWages);
						}
						break;
					default:
						break;
					}
					// 添加细节
					SalaryStatisticsDetail statisticsDetail = new SalaryStatisticsDetail();
					statisticsDetail.setSchemeTitle(detail.getSchemeTitle());
					statisticsDetail.setLinkedDataId(detail.getLinkedDataId());
					statisticsDetail.setLinkedDataType(detail.getLinkedDataType());
					statisticsDetail.setLinkedDataTitle(detail.getLinkedDataTitle());
					statisticsDetail.setStructType(detail.getStructType());
					statisticsDetail.setSchemeSalary(Math.abs(secondWages));
					mStatistics.addDetailItem(statisticsDetail);
				}

			}
			totalWages = totalWages + secondWages;
		}
		
		// 计算员工奖惩
		float awardWages = computeSingleEmployeeAward(mWork, mCalendar,mStatistics);
		if(awardWages > 0){
			totalWages += awardWages;
		}else if(awardWages < 0){
			totalWages -= awardWages;
		}
		// 设置计算结果
		mStatistics.setActaulPaySalary(totalWages);
		mStatistics.setCompanyPaySalary(companyPayWages[0]);
		try {
			salaryStatisticService.save(mStatistics);
			successCount++;
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error(e);
			}
			failureCount++;
		}
	}

	/**
	 * 计算社保
	 * 
	 * @param detail
	 * @param lazyDetails
	 * @param mWork
	 * @param performances
	 * @param type
	 * @param mCalendar
	 * @param totalWages
	 * @param companyPayWages
	 *            公司缴费
	 * @return
	 */
	private float computeInsurance(SalaryStructureDetail detail, Set<Object> lazyDetails, EmployeeinfoWork mWork, List<SalaryPerformance> performances, ExaminePeriodEnum type,
			int year, int month, float totalWages, Float[] companyPayWages) {
		float itemWages = 0f;
		if(detail.getLinkedDataId() <= 0){
			return itemWages;
		}
		SalarySocialInsurance insurance = salaryInsuranceService.get(detail.getLinkedDataId());
		Set<SalarySocialInsuranceDetail> socialInsuranceDetails = insurance.getDetails();
		if (socialInsuranceDetails != null && socialInsuranceDetails.size() > 0) {
			for (SalarySocialInsuranceDetail salarySocialInsuranceDetail : socialInsuranceDetails) {
				if (salarySocialInsuranceDetail.getProjectType() == SalaryInsurancePayEnum.personal) {
					// 公积金
					Long periodId = 0l;
					ExamStatistics mExamStatistics;
					SalaryLinkedEnum linkedEnum = null;
					if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
						linkedEnum = insurance.getFundBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
						linkedEnum = insurance.getBirthInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
						linkedEnum = insurance.getInjuryInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
						linkedEnum = insurance.getMedicalInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
						linkedEnum = insurance.getOldageInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
						linkedEnum = insurance.getUnemploymentInsuranceBaseType();
					}
					
					switch (linkedEnum) {
					case no_linked:
						if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
							itemWages += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
							itemWages += insurance.getBirthBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
							itemWages += insurance.getInjuryBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
							itemWages += insurance.getMedicalInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
							itemWages += insurance.getOldageBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
							itemWages += insurance.getUnemploymentBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
//						if (salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund) {
//							itemWages += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						} else {
//							itemWages += insurance.getInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						}
						break;
					case employee_base_salary: // 基本工资
						itemWages += mWork.getGradeLevel().getGradePay() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						break;
					case employee_performance: // 绩效
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									itemWages += mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100)
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case employee_salary_performance:
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									itemWages += (mWork.getGradeLevel().getGradePay() + mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100))
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case salary_framework:
						if (lazyDetails != null && totalWages < 0) {
							itemWages = -1;
							lazyDetails.add(detail); // 与薪资总和挂勾
						} else if (totalWages > 0) {
							itemWages += totalWages * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
						break;
					default:
						break;
					}
					//
				} else if (salarySocialInsuranceDetail.getProjectType() == SalaryInsurancePayEnum.company && companyPayWages != null && companyPayWages.length > 0) { // 公司缴费
					// 公积金
					Long periodId = 0l;
					ExamStatistics mExamStatistics;
					SalaryLinkedEnum linkedEnum = null;
					if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
						linkedEnum = insurance.getFundBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
						linkedEnum = insurance.getBirthInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
						linkedEnum = insurance.getInjuryInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
						linkedEnum = insurance.getMedicalInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
						linkedEnum = insurance.getOldageInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
						linkedEnum = insurance.getUnemploymentInsuranceBaseType();
					}
					switch (linkedEnum) {
					case no_linked:
						if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
							companyPayWages[0] += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
							companyPayWages[0] += insurance.getBirthBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
							companyPayWages[0] += insurance.getInjuryBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
							companyPayWages[0] += insurance.getMedicalInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
							companyPayWages[0] += insurance.getOldageBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
							companyPayWages[0] += insurance.getUnemploymentBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
//						if (salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund) {
//							companyPayWages[0] += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						} else {
//							companyPayWages[0] += insurance.getInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						}
						break;
					case employee_base_salary: // 基本工资
						companyPayWages[0] += mWork.getGradeLevel().getGradePay() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						break;
					case employee_performance: // 绩效
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									companyPayWages[0] += mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100)
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case employee_salary_performance:
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									companyPayWages[0] += (mWork.getGradeLevel().getGradePay() + mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100))
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case salary_framework:
						if (totalWages > 0) {
							companyPayWages[0] += totalWages * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
						break;
					default:
						break;
					}
					//
				}
			}
		}
		return itemWages;
	}

	/**
	 * 计算绩效奖金
	 * 
	 * @param mWork
	 * @param performances
	 * @param type
	 * @param mCalendar
	 * @return
	 */
	private float computePerformance(EmployeeinfoWork mWork, List<SalaryPerformance> performances, ExaminePeriodEnum type, int year, int month) {
		float itemWages = 0f;
		Long periodId = 0l;
		ExamStatistics mExamStatistics;
		periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
		mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
		if (mExamStatistics != null && mExamStatistics.getScore() != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
			for (SalaryPerformance performance : performances) {
				if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
					itemWages = mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100);
				}
			}
		}
		return itemWages;
	}

	/**
	 * 计算个人所税
	 * 
	 * @param detail
	 * @param lazyDetails
	 * @param mWork
	 * @param performances
	 * @param type
	 * @param mCalendar
	 * @param totalWages
	 * @return
	 */
	private float computePersonalTax(SalaryStructureDetail detail, Set<Object> lazyDetails, EmployeeinfoWork mWork, List<SalaryPerformance> performances, ExaminePeriodEnum type,
			int year, int month, float totalWages) {
		float itemWages = 0f;
		if(detail.getLinkedDataId() <=0 ){
			return itemWages;
		}
		SalaryIndividualTax mIndividualTax = individualTaxService.get(detail.getLinkedDataId());
		float insuranceWages = 0f;
		if (mIndividualTax.isRemoveInsurance()) { // 移出四金
			SalaryStructureDetail insuranceDetail = salaryStructService.getStructureDetailByIdAndLnkType(detail.getSalaryStructure().getId(), SalaryFrameworkEnum.social_insurance);
			if (insuranceDetail != null) {
				insuranceWages = computeInsurance(insuranceDetail, null, mWork, performances, type, year, month, totalWages, null);
				if (insuranceWages <= 0 && totalWages < 0) {
					lazyDetails.add(detail); // 写入重新计算规则
					return itemWages;
				}
			}
		}
		// 开始正式计算
		switch (mIndividualTax.getLinkedDataType()) {
		case no_linked:
			itemWages = mIndividualTax.getCostBase() - insuranceWages;
			break;
		case employee_base_salary:
			itemWages = mWork.getGradeLevel().getGradePay() - insuranceWages;
			break;
		case employee_performance:
			itemWages = computePerformance(mWork, performances, type, year, month) - insuranceWages;
			break;
		case employee_salary_performance:
			itemWages = mWork.getGradeLevel().getGradePay() + computePerformance(mWork, performances, type, year, month) - insuranceWages;
			break;
		case salary_framework:
			if (totalWages < 0) {
				itemWages = -1;
				lazyDetails.add(detail);
				return itemWages;
			} else {
				itemWages = totalWages - insuranceWages;
			}
		default:
			break;
		}
		// 个税扣出方案
		if (individualTaxRadix == null) {
			itemWages = itemWages <= taxBase ? 0 : itemWages - taxBase;
		} else {
			itemWages = itemWages <= individualTaxRadix.getRadix() ? 0 : itemWages - individualTaxRadix.getRadix();
		}
		// if (mIndividualTax.getLinkedDataType() != SalaryLinkedEnum.no_linked)
		// {
		// 1 不超过1500元的部分 3% 0
		// 2 超过1500元至4500元的部分 10% 105
		// 3 超过4500元至9000元的部分 20% 555
		// 4 超过9000元至35000元的部分 25% 1005
		// 5 超过35000元至55000元的部分 30% 2755
		// 6 超过55000元至80000元的部分 35% 5505
		// 7 超过80000的部分 45% 13505
		if (individualTaxRules == null || individualTaxRules.size() <= 0) {
			if (itemWages <= 1500) {
				itemWages = itemWages * 0.03f;
			} else if (itemWages <= 4500) {
				itemWages = itemWages * 0.1f - 105;
			} else if (itemWages <= 9000) {
				itemWages = itemWages * 0.2f - 555;
			} else if (itemWages <= 35000) {
				itemWages = itemWages * 0.25f - 1005;
			} else if (itemWages <= 55000) {
				itemWages = itemWages * 0.3f - 2755;
			} else if (itemWages <= 80000) {
				itemWages = itemWages * 0.35f - 5505;
			} else {
				itemWages = itemWages * 0.45f - 13505;
			}
		} else {
			for (SalaryIndividualTaxRule individualTaxRule : individualTaxRules) {
				if (individualTaxRule.getAmountEnd() == -1 && itemWages > individualTaxRule.getAmountStart()) {
					itemWages = itemWages * (individualTaxRule.getTaxRate() / 100) - individualTaxRule.getFastCutValue();
					break;
				} else if (itemWages > individualTaxRule.getAmountStart() && itemWages <= individualTaxRule.getAmountEnd()) {
					itemWages = itemWages * (individualTaxRule.getTaxRate() / 100) - individualTaxRule.getFastCutValue();
					break;
				}
			}
		}
		// }
		return itemWages;
	}

	/**
	 * 计算社保-自定义
	 * 
	 * @param detail
	 * @param lazyDetails
	 * @param mWork
	 * @param performances
	 * @param type
	 * @param mCalendar
	 * @param totalWages
	 * @return
	 */
	private float computeInsuranceWithCustomMode(SalaryCustomDetail detail, Set<Object> lazyDetails, EmployeeinfoWork mWork, List<SalaryPerformance> performances,
			ExaminePeriodEnum type, int year, int month, float totalWages, Float[] companyPayWages) {
		float itemWages = 0f;
		SalarySocialInsurance insurance = salaryInsuranceService.get(detail.getLinkedDataId());
		Set<SalarySocialInsuranceDetail> socialInsuranceDetails = insurance.getDetails();
		if (socialInsuranceDetails != null && socialInsuranceDetails.size() > 0) {
			for (SalarySocialInsuranceDetail salarySocialInsuranceDetail : socialInsuranceDetails) {
				if (salarySocialInsuranceDetail.getProjectType() == SalaryInsurancePayEnum.personal) {
					// 公积金
					Long periodId = 0l;
					ExamStatistics mExamStatistics;
					SalaryLinkedEnum linkedEnum = null;
					if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
						linkedEnum = insurance.getFundBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
						linkedEnum = insurance.getBirthInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
						linkedEnum = insurance.getInjuryInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
						linkedEnum = insurance.getMedicalInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
						linkedEnum = insurance.getOldageInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
						linkedEnum = insurance.getUnemploymentInsuranceBaseType();
					}
					switch (linkedEnum) {
					case no_linked:
//						if (salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund) {
//							itemWages += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						} else {
//							itemWages += insurance.getInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						}
						if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
							itemWages += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
							itemWages += insurance.getBirthBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
							itemWages += insurance.getInjuryBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
							itemWages += insurance.getMedicalInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
							itemWages += insurance.getOldageBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
							itemWages += insurance.getUnemploymentBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
						break;
					case employee_base_salary: // 基本工资
						itemWages += mWork.getGradeLevel().getGradePay() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						break;
					case employee_performance: // 绩效
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									itemWages += mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100)
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case employee_salary_performance:
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									itemWages += (mWork.getGradeLevel().getGradePay() + mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100))
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case salary_framework:
						if (lazyDetails != null && totalWages < 0) {
							itemWages = -1;
							lazyDetails.add(detail); // 与薪资总和挂勾
						} else if (totalWages > 0) {
							itemWages += totalWages * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
						break;
					default:
						break;
					}
					//
				} else if (salarySocialInsuranceDetail.getProjectType() == SalaryInsurancePayEnum.company) {

					// 公积金
					Long periodId = 0l;
					ExamStatistics mExamStatistics;
					SalaryLinkedEnum linkedEnum = null;
					if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund){
						linkedEnum = insurance.getFundBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
						linkedEnum = insurance.getBirthInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
						linkedEnum = insurance.getInjuryInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
						linkedEnum = insurance.getMedicalInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
						linkedEnum = insurance.getOldageInsuranceBaseType();
					}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
						linkedEnum = insurance.getUnemploymentInsuranceBaseType();
					}
					switch (linkedEnum) {
					case no_linked:
//						if (salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund && companyPayWages != null && companyPayWages.length > 0) {
//							companyPayWages[0] += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						} else {
//							companyPayWages[0] += insurance.getInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
//						}
						if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.fund && companyPayWages != null && companyPayWages.length > 0){
							companyPayWages[0] += insurance.getFundBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.birthinsurance){
							companyPayWages[0] += insurance.getBirthBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.injuryinsurance){
							companyPayWages[0] += insurance.getInjuryBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.medicalinsurance){
							companyPayWages[0] += insurance.getMedicalInsuranceBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.oldageinsurance){
							companyPayWages[0] += insurance.getOldageBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}else if(salarySocialInsuranceDetail.getInsuranceType() == SalaryInsuranceTypeEnum.unemploymentinsurance){
							companyPayWages[0] += insurance.getUnemploymentBase() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
						break;
					case employee_base_salary: // 基本工资
						companyPayWages[0] += mWork.getGradeLevel().getGradePay() * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						break;
					case employee_performance: // 绩效
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									companyPayWages[0] += mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100)
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case employee_salary_performance:
						periodId = examPeriodService.getExamPeriodByTypeAndYMonthly(type, year, month);
						mExamStatistics = examStatisticsService.getExamStatistics(periodId, mWork.getId());
						if (mExamStatistics != null && mExamStatistics.getScore() > 0 && performances != null && performances.size() > 0) {
							for (SalaryPerformance performance : performances) {
								if (mExamStatistics.getScore() >= performance.getScoreStart() && mExamStatistics.getScore() <= performance.getScoreEnd()) {
									companyPayWages[0] += (mWork.getGradeLevel().getGradePay() + mWork.getGradeLevel().getPerformance() * (performance.getPercentage() / 100))
											* (salarySocialInsuranceDetail.getOccupancyRate() / 100);
								}
							}
						}
						break;
					case salary_framework:
						if (totalWages > 0) {
							companyPayWages[0] += totalWages * (salarySocialInsuranceDetail.getOccupancyRate() / 100);
						}
						break;
					default:
						break;
					}
					//

				}
			}
		}
		return itemWages;
	}

	/**
	 * 自定义方案中的个税计算
	 * 
	 * @param detail
	 * @param lazyDetails
	 * @param mWork
	 * @param performances
	 * @param type
	 * @param mCalendar
	 * @param totalWages
	 * @return
	 */
	private float computePersonalTaxWithCustomMode(SalaryCustomDetail detail, Set<Object> lazyDetails, EmployeeinfoWork mWork, List<SalaryPerformance> performances,
			ExaminePeriodEnum type, int year, int month, float totalWages) {
		float itemWages = 0f;
		SalaryIndividualTax mIndividualTax = individualTaxService.get(detail.getLinkedDataId());
		float insuranceWages = 0f;
		if (mIndividualTax == null) {
			return insuranceWages;
		}

		if (mIndividualTax.isRemoveInsurance()) { // 移出四金
			SalaryCustomDetail insuranceDetail = salaryCustomService.getCustomDetailByIdAndLnkType(detail.getSalaryCustom().getId(), SalaryFrameworkEnum.social_insurance);
			if (insuranceDetail != null) {
				insuranceWages = computeInsuranceWithCustomMode(insuranceDetail, null, mWork, performances, type, year, month, totalWages, null);
				if (insuranceWages <= 0 && totalWages < 0) {
					lazyDetails.add(detail); // 写入重新计算规则
					return itemWages;
				}
			}
		}
		// 开始正式计算
		switch (mIndividualTax.getLinkedDataType()) {
		case no_linked:
			itemWages = mIndividualTax.getCostBase() - insuranceWages;
			break;
		case employee_base_salary:
			itemWages = mWork.getGradeLevel().getGradePay() - insuranceWages;
			break;
		case employee_performance:
			itemWages = computePerformance(mWork, performances, type, year, month) - insuranceWages;
			break;
		case employee_salary_performance:
			itemWages = mWork.getGradeLevel().getGradePay() + computePerformance(mWork, performances, type, year, month) - insuranceWages;
			break;
		case salary_framework:
			if (totalWages < 0) {
				itemWages = -1;
				lazyDetails.add(detail);
				return itemWages;
			} else {
				itemWages = totalWages - insuranceWages;
			}
			break;
		default:
			break;
		}
		// 个税扣出方案
		if (individualTaxRadix == null) {
			itemWages = itemWages <= taxBase ? 0 : itemWages - taxBase;
		} else {
			itemWages = itemWages <= individualTaxRadix.getRadix() ? 0 : itemWages - individualTaxRadix.getRadix();
		}
		// if (mIndividualTax.getLinkedDataType() != SalaryLinkedEnum.no_linked)
		// {
		// 1 不超过1500元的部分 3% 0
		// 2 超过1500元至4500元的部分 10% 105
		// 3 超过4500元至9000元的部分 20% 555
		// 4 超过9000元至35000元的部分 25% 1005
		// 5 超过35000元至55000元的部分 30% 2755
		// 6 超过55000元至80000元的部分 35% 5505
		// 7 超过80000的部分 45% 13505
		if (individualTaxRules == null || individualTaxRules.size() <= 0) {
			if (itemWages <= 1500) {
				itemWages = itemWages * 0.03f;
			} else if (itemWages <= 4500) {
				itemWages = itemWages * 0.1f - 105;
			} else if (itemWages <= 9000) {
				itemWages = itemWages * 0.2f - 555;
			} else if (itemWages <= 35000) {
				itemWages = itemWages * 0.25f - 1005;
			} else if (itemWages <= 55000) {
				itemWages = itemWages * 0.3f - 2755;
			} else if (itemWages <= 80000) {
				itemWages = itemWages * 0.35f - 5505;
			} else {
				itemWages = itemWages * 0.45f - 13505;
			}
		} else {
			for (SalaryIndividualTaxRule individualTaxRule : individualTaxRules) {
				if (individualTaxRule.getAmountEnd() == -1 && itemWages > individualTaxRule.getAmountStart()) {
					itemWages = itemWages * (individualTaxRule.getTaxRate() / 100) - individualTaxRule.getFastCutValue();
					break;
				} else if (itemWages > individualTaxRule.getAmountStart() && itemWages <= individualTaxRule.getAmountEnd()) {
					itemWages = itemWages * (individualTaxRule.getTaxRate() / 100) - individualTaxRule.getFastCutValue();
					break;
				}
			}
		}
		// }
		return itemWages;
	}
	
	//计算员工奖惩
	private float computeSingleEmployeeAward(EmployeeinfoWork mWork, Calendar mCalendar,SalaryStatistics mStatistics){
		float itemWages = 0f;
		LimitedList<ExamAward> awards = examAwardService.searchExamAwardByWorkIdMonth(mWork.getId(),
				mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH), null, null);
		if(awards != null && awards.size() > 0){
			Iterator<ExamAward> iterator = awards.iterator();
			while(iterator.hasNext()){
				ExamAward award = iterator.next();
				if(award.getAuditStatus() == AuditStatus.pass_audit){
					SalaryStatisticsDetail awardDetail = new SalaryStatisticsDetail();
					awardDetail.setSchemeTitle(award.getExamAwardItem().getTitle());
					if(award.getAwardType() == 0){	//奖励
						awardDetail.setStructType(SalaryStructureEnum.subsidy);
						itemWages += award.getExamAwardItem().getMoney();
					}else{
						awardDetail.setStructType(SalaryStructureEnum.detain);
						itemWages -= award.getExamAwardItem().getMoney();
					}
					
					awardDetail.setLinkedDataId(award.getId());
					awardDetail.setLinkedDataType(SalaryFrameworkEnum.award);
					awardDetail.setLinkedDataTitle(award.getExamAwardItem().getTitle());
					awardDetail.setSchemeSalary(Math.abs(itemWages));
					mStatistics.addDetailItem(awardDetail);
					
					//回写奖惩状态
					award.setStatus(1);
					examAwardService.saveExamAward(award);
				}
			}
		}
		return itemWages;
	}

	public SalaryFrameworkEnum getLinkedDataType() {
		return linkedDataType;
	}

	public void setLinkedDataType(SalaryFrameworkEnum linkedDataType) {
		this.linkedDataType = linkedDataType;
	}

	public List<SalaryLinkedPojo> getLinkedPojos() {
		return linkedPojos;
	}

	public void setLinkedPojos(List<SalaryLinkedPojo> linkedPojos) {
		this.linkedPojos = linkedPojos;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public Long getWorkId() {
		return workId;
	}

	public void setWorkId(Long workId) {
		this.workId = workId;
	}

	public Long getDutyId() {
		return dutyId;
	}

	public void setDutyId(Long dutyId) {
		this.dutyId = dutyId;
	}

	public int getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}

	public int getCurrentPos() {
		return currentPos;
	}

	public void setCurrentPos(int currentPos) {
		this.currentPos = currentPos;
	}

	public SalaryIndividualTaxRadix getIndividualTaxRadix() {
		return individualTaxRadix;
	}

	public void setIndividualTaxRadix(SalaryIndividualTaxRadix individualTaxRadix) {
		this.individualTaxRadix = individualTaxRadix;
	}

	public List<SalaryIndividualTaxRule> getIndividualTaxRules() {
		return individualTaxRules;
	}

	public void setIndividualTaxRules(List<SalaryIndividualTaxRule> individualTaxRules) {
		this.individualTaxRules = individualTaxRules;
	}
}
